--
-- Author:      name
-- DateTime:    2022-08-21 15:57:48
-- Description: 游戏主逻辑
-- 比赛场的桌子

local FSM = require("fsm")
local cjson = require("cjson")

local table_insert = table.insert
local table_remove = table.remove
local math_floor = math.floor
local math_random = math.random


--------------------------------class---------------------------------
local DeskBase = require("games.common.desk")
local Desk = DeskBase:extend("Desk")

function Desk:ctor()
	--注意写上这个是为了让更新基类时，对象能同步上变更，但要注意同名函数可能会产生覆盖
	self.super:setModuleName("games.common.desk")
	Desk.super.ctor(self)
	self:register()
end

function Desk:register()

end

----------------------------------------------------------------------------------------------
---------开始游戏
---------------------------------------------------------------------------------------------- 
function Desk:init()
	print("___初始化游戏桌子___", g.tid)
	self.sb = nil
	self.bb = nil --大盲注
	self.closed = false --桌子关闭
	self.cur_oper = nil --当前操作者
	self.next_oper = nil --下一个操作者
	self.banker = nil --当前庄家
	self.banker_seat_id = nil --庄位置
	self.sb_seat_id = nil --庄位置
	self.bb_seat_id = nil --庄位置
	self.cur_oper_seat_id = nil --当前操作者位置
	self.total_bet = 0 --当前局总下注
	self.cur_bet = 0 --当前下注额度
	self.stage_bet = 0 --当前轮下注额度, 最小跟注
	self.min_raise_bet = 0 --最小加注值
	self.stage_bet_count = 0 --本局加注次数
	self.follow_bet = 0 --当前需要最小跟注
	self.last_raise_bet = 0 --本轮最后一个加注的额度

	self.common_cards = {} --公牌
	self.pots = {} --主池和边池
	self.pot_seats = {} --每个池对应的玩家位置{{1,2,4}, {}}
	self.seat_bet = {} --各位置下注金额
	self.cur_stage = nil --当前状态
	self.start_play_limit = 2 --开始游戏需要的人数
	self.bb_user = nil --大盲玩家
	self.sb_user = nil --小盲玩家
	self.allined = false --所有人allin
	self.user_show_cards = {} --要开牌的玩家
	self.pre_bet = 0 --当前前注

	self.oper_timer = new("base.timer")
	self.oper_timer_id = 0 --定时器id
	--比赛信息
	self.started = false --可以开始的标记
	self.pre_bet = 0 --当前前注
	self.blind_level = 1 --盲注等级
	self.blind_cfg = nil --盲注等级配置
	self.up_blind_time = 999 --涨盲时间
	self.blinds = {} --盲注表
	--状态名
	self.s_stage_start = "start"
	self.s_stage_preflop   = "preflop"
	self.s_stage_flop      = "flop"
	self.s_stage_turn      = "turn"
	self.s_stage_river     = "river"
	self.s_stage_over 	   = "over"
	self.s_stage_rest 	   = "rest"
	--状态时间
	self.stateTime = {
		start = 1,		--开始
		oper = 15,		--操作时间
		over = 5, 		--结束游戏
		rest = 1,		--等待
	}
	--游戏状态
	self.state_num ={
		[self.s_stage_start] = 1,
		[self.s_stage_preflop] = 2,
		[self.s_stage_flop] = 3,
		[self.s_stage_turn] = 4,
		[self.s_stage_river] = 5,
		[self.s_stage_over] = 6,
		[self.s_stage_rest] = 7,
	}
	--休息，开始玩家操作，抢庄, 下注，发牌，结算
	--state1 --eventName --state2 --callback
	self.stateTable = {
		{"rest", 	"to_start", 	"start", 	function() self:stStart() end }, --state start
		{"start", 	"to_preflop", 	"preflop", 	function() self:stPreflop() end },
		{"preflop", "to_flop",		"flop", 	function() self:stFlop() end },
		{"flop", 	"to_turn",		"turn", 	function() self:stTurn() end },
		{"turn", 	"to_river",		"river", 	function() self:stRiver() end },
		{"*", 		"to_over",		"over", 	function() self:stOver() end },
		{"*", 		"to_rest",		"rest", 	function() self:stReset() end },
	}
	self.fsm = FSM.new(self.stateTable)
	--启动状态机
	self.fsm:set("over")
	self.fsm:fire("to_rest")


	g.loop(100, function()
		local cd_time = self.oper_timer:getCD(self.oper_timer_id)
		if cd_time and cd_time>0 then
			--print("#########"..g.tid, self:getStage(), cd_time)
		end
		--self:upBlindTime()
		if self.started then
			if self.up_blind_time and self.up_blind_time > 0 then
				self.up_blind_time = self.up_blind_time - 1
			end
		end
	end)
end

function Desk:getStateTime()
	return self.stateTime
end

--重置数据
function Desk:reset()
	self.cur_oper = nil
	self.total_bet = 0 --当前局总下注
	self.cur_bet = 0
	self.cur_stage = nil --当前状态
	self.stage_bet = 0
	self.min_raise_bet = 0
	self.common_cards = {}
	self.seat_bet = {}
	self.seat_count = g.room_cfg.seat_count or 9
	self.allined = false --所有人allin
	self.user_show_cards = {}
	self.pre_bet = 0 --当前前注
	self.follow_bet = 0 --当前需要最小跟注
	self.last_raise_bet = 0 --本轮最后一个加注的额度

	self.stage_logs = {} --每个状态的下注情况
	self.round_start_time = 0 --每局开始时间
	self.total_fee = 0 --每局的税
	--大小盲
	if self.blind_cfg then
		self.sb = self.blind_cfg.small_blind
		self.bb = self.sb * 2
	end
	local users = g.user_mgr:getUsers()
	for _, user  in pairs(users) do
		user:chipInit(user.s_status_init)
	end
	self.pots = {} --主池和边池
	self.pot_seats = {} --每个池对应的玩家位置
	for i=1, self.seat_count do
		table_insert(self.pots, 0)
		table_insert(self.pot_seats, {})
	end
	self.players = {} --参与游戏的玩家
end

--下一个操作者
function Desk:findNextOper()
	--应该有先有庄，从庄的下一位开始
	local seat_id = self.cur_oper_seat_id or self.banker_seat_id
	if not self.cur_oper_seat_id and self:getStage() == self.s_stage_preflop then
		--print("####1#findNextOper#####")
		--牌前是大盲下一位开始下注
		seat_id = self.bb_user:getSeatId()
	end
	--print("####2#findNextOper##seat_id###", seat_id)

	local count = seat_id + self.seat_count
	local tmp_seat_id = 0
	for i=seat_id+1, count do
		tmp_seat_id = i % (self.seat_count + 1)
		local user = g.user_mgr:getSeatUser(tmp_seat_id)
		if user and user:isGaming() then
			--下注状态
			local action = user:getAction()
			if action == user.s_bet_init or action == user.s_bet_pre or
					(user:getStageBet() < self.stage_bet and action ~= user.s_bet_fold and action ~= user.s_bet_allin) or
					(user:getStageBet() == self.stage_bet and action == user.s_bet_bb) then
				--print("####3#findNextOper##seat_id###", tmp_seat_id, user:getUid())
				return user
			end
		end
	end
	return
end

--取池子
function Desk:getPot()
	local pots = {}
	if self:getStage() == self.s_stage_rest then
		return pots
	end
	if self.pots[1] == 0 then
		--没有分池的情况
		print("##########pushPot1 ", self.total_bet)
		if self:getStage() == self.s_stage_preflop then
			return pots
		end
		table_insert(pots, {pot=self.total_bet})
	else
		print("##########pushPot2 ", self.pots[1])
		for k, v in pairs(self.pots) do
			local pot = {pot = v}
			table_insert(pots, pot)
		end
	end
	return pots
end

function Desk:getCommonCards()
	local cards = {}
	for k, v in pairs(self.common_cards) do
		table.insert(cards, {card=v})
	end
	return cards
end



-------------------------------------------------------------------------------
-- 推送消息
-------------------------------------------------------------------------------
-- 下注计算
function Desk:checkBet(seat_id, chips)
	local flag = false
	local user = g.user_mgr:getSeatUser(seat_id)
	if not user then return flag end
	local uid = user:getUid()
	--如果只剩下一个人在玩，下注都是无效的
	if g.user_mgr:getPlayingUserNum() <= 1 then
		g.log:deskInfo(user:getUid(), "checkBet player user num <= 1")
		return false
	end
	-- 弃牌
	if chips < 0 then
		flag = true
		return flag
	end
	-- allin
	local chip = user:getChip()
	if chip == chips then
		flag = true
		return flag
	end
	if chip < chips then -- 不够下注
		g.log:deskWarn(uid, "checkBet chip not enough")
		return flag
	end
	-- check
	local stage_bet = user:getStageBet() --当前轮已下注
	if chips == 0 then
		if stage_bet ~= self.stage_bet then -- 看牌错误
			g.log:deskWarn(uid, "checkBet check stage_bet ~= self.stage_bet", stage_bet, self.stage_bet)
			return false
		end
		flag = true
		return flag
	end

	stage_bet = chips + stage_bet
	-- 跟注
	if stage_bet == self.stage_bet then
		flag = true
		return flag
	end
	-- 下(加)注 必须大于 大盲
	if stage_bet < self.bb then
		g.log:deskWarn(uid, "checkBet stage_bet < self.bb", seat_id, chips, stage_bet, self.bb)
		return flag
	end

	-- 等于跟注值  或者 >= 最小加注值 都能下
	-- 翻牌前 跟注值 必须 等于 大盲
	if self.stage_bet > 0 and self.stage_bet < self.bb and self:getStage() == self.s_stage_preflop then
		self.stage_bet = self.bb
		--self.min_raise_bet = self.bb
	end
	if stage_bet == self.stage_bet or stage_bet >= self.min_raise_bet then
		flag = true
		return flag
	end
	g.log:deskWarn(uid, "checkBet faild", seat_id, chips, stage_bet, stage_bet, self.bb)
	return flag
end

--下注
function Desk:betting(seat_id, chips, act)
	print("######betting######", seat_id, chips, act)
	local flag = false
	local user = g.user_mgr:getSeatUser(seat_id)
	if not user then return flag end
	local uid = user:getUid()
	if not act and self:checkBet(seat_id, chips) == false then
		g.log:deskWarn(uid, "betting faild", seat_id, chips, act)
		return false
	end
	local user_chip = user:getChip()
	local action = 0
	if chips < 0 then
		--弃牌
		user:setStatus(user.s_status_giveup)
		action = user.s_bet_fold
		local folds = {
			[self.s_stage_preflop] = 1,
			[self.s_stage_flop] = 2,
			[self.s_stage_turn] = 3,
			[self.s_stage_river] = 4,
		}
		local num = folds[self.cur_stage] or 1
		user:setFold(num)
	elseif chips == 0 then
		--check
		action = user.s_bet_check
	else
		local u_stage_bet =  user:getStageBet() + chips
		if u_stage_bet <= self.stage_bet then
			--跟注
			action = user.s_bet_call_follow
		else
			--加注
			action = user.s_bet_raise
			if self.stage_bet_count == 0 then
				action = user.s_bet_call_first
			end
			self.stage_bet_count = self.stage_bet_count + 1
			self.last_raise_bet = u_stage_bet - self.stage_bet --本轮最后一个加注的额度
			user:addStageRaiseNum()
		end
		if u_stage_bet >= self.min_raise_bet then
			--最小加注值
			self.min_raise_bet = u_stage_bet * 2 - self.stage_bet
		end
		user:subChip(chips)
		if u_stage_bet > self.stage_bet then
			self.stage_bet = u_stage_bet
		end
	end
	if act then
		action = act
	end
	user:setAction(action)
	if chips > 0 and user:getChip() == 0 then
		user:setAction(user.s_bet_allin)
	end
	if chips > user_chip then
		chips = user_chip
	end
	if chips >= 0 then
		self.total_bet = self.total_bet + chips
		local u_stage_bet =  user:getStageBet() + chips
		user:setStageBet(u_stage_bet)
		user:addSeatBet(chips)
		user:addTotalBet(chips)
		self.seat_bet[seat_id] = (self.seat_bet[seat_id] or 0) + chips
	end
	user:setCurBet(chips)
	self:addBetLogs(user)
	self:pushBet(chips, user)

	g.log:deskInfo(uid, string.format("betting sid:%s, uchips:%s, chips:%s, act:%s,	u_stage_bet=%s, u_host_count=%s, r_stage_bet=%s, r_min_raise_bet=%s ",
			seat_id, user:getChip(), chips, user.s_bet_str[action], user:getStageBet(), user:getNoOperRound(), self.stage_bet, self.min_raise_bet))

	return true

end

--下一个庄
function Desk:setBanker()
	self.banker_seat_id = self.banker_seat_id or 0
	local seat_id = self.banker_seat_id
	local count = self.banker_seat_id + self.seat_count
	local tmp_seat_id = 0
	for i=seat_id+1, count do
		tmp_seat_id = i % (self.seat_count + 1)
		local user = g.user_mgr:getSeatUser(tmp_seat_id)
		if user and user:isGaming() then
			if self.old_player_num > 2 and self.sb_seat_id then
				self.banker_seat_id = self.sb_seat_id
				break
			end
			self.banker = user
			self.banker_seat_id = tmp_seat_id
			--print("######banker##tmp_seat_id##", tmp_seat_id)
			break
		end
	end

	--应该有先有庄，从庄的下一位是大盲，小盲
	local seat_id = self.banker_seat_id
	local count = seat_id + self.seat_count
	local tmp_seat_id = 0
	for i=seat_id+1, count do
		tmp_seat_id = i % (self.seat_count + 1)
		local user = g.user_mgr:getSeatUser(tmp_seat_id)
		if user and user:isGaming() then
			self.sb_user = user
			self.sb_seat_id = tmp_seat_id
			--print("######sb##tmp_seat_id##", tmp_seat_id)
			break
		end
	end
	seat_id = self.sb_user:getSeatId()
	count = seat_id + self.seat_count
	for i=seat_id+1, count do
		tmp_seat_id = i % (self.seat_count + 1)
		--g.log:info("#########sb######", i, tmp_seat_id, self.seat_count)
		local user = g.user_mgr:getSeatUser(tmp_seat_id)
		if user and user:isGaming() then
			self.bb_user = user
			self.bb_seat_id = tmp_seat_id
			--print("######bb##tmp_seat_id##", tmp_seat_id)
			break
		end
	end
end

--改变状态
function Desk:changeStage(state)
	if not state then
		return
	end
	self.oper_timer:deltimer(self.oper_timer_id)
	g.fork(function()
		--g.sleep(1)
		self:calcPots()
		self.cur_stage = state
		self.cur_oper = nil
		self.cur_oper_seat_id = nil
		self.stage_bet = 0 --当前轮下注额度
		self.min_raise_bet = self.bb
		local users = self:getPlayers()
		for _, user in pairs(users) do
			if user:getAction() ~= user.s_bet_allin then
				user:setAction(user.s_bet_init)
			end
			user:setStageBet(0)
		end
		--g.log:finfo("changeStage:%s", state)
		self.fsm:fire("to_"..state)
		local state_num = self:getStageNum()
		if state_num > self.state_num[self.s_stage_start] and state_num < self.state_num[self.s_stage_rest] then
			self:addStageLogs()
		end
	end)
end

function Desk:nextStage(sleep_time)
	if sleep_time then
		g.sleep(sleep_time)
	end
	if self.cur_stage == self.s_stage_over or self.cur_stage == self.s_stage_rest then
		--这2个状态不能在这里切换
		return
	end
	local state = 0
	if not self.cur_stage then
		state = self.s_stage_start
	else
		local state_num = self.state_num[self.cur_stage]
		--print("###Desk nextStage ", self.cur_stage, state_num)
		state_num = (state_num + 1) % #self.stateTable
		local state_info = self.stateTable[state_num]
		state = state_info[3]
	end
	--self.oper_timer_id = 0
	self:changeStage(state)
end



-------------------------------------------------------------------------------
-- 状态
-------------------------------------------------------------------------------

--开始
function Desk:stStart()
	g.log:deskInfo(0, "onStart")
	self.round_start_time = g.time()
	self.round_num = self.round_num + 1
	self.old_player_num = self:getOldPlayerNum() --上局在玩的人数
	g.rule:shuffle() --洗牌
	self.user_show_cards = {} --清掉要亮的牌
	self.final_cards = g.rule:getCommonCards(5)
	g.log:deskWarn(0, "final_cards", self.final_cards)
	--设置玩家状态
	local users = g.user_mgr:getSeatUsers()
	for _, user in pairs(users) do
		user:setStatus(user.s_status_gaming)
		user:addRound()
		--参与过这一局的都记录下
		self:addPlayer(user)
	end
	--大小盲
	self.sb = self.blind_cfg.small_blind
	self.bb = self.sb * 2
	self:createRoundId()
	self:sendAddRound()
	self:setBanker() --确定庄大小盲注位置
	--给玩家发广播消息
	self:pushStart()
	local callback = function ()
		self:changeStage(self.s_stage_preflop)
	end
	self.oper_timer_id = self.oper_timer:timeout(self.stateTime.start, callback)

end

--玩家操作
function Desk:playerOper(stage)
	g.log:deskInfo(0, "playerOper", stage)
	--当可操作人数少于2时直接跳过(2个人玩有1个弃牌
	local oper_count = 0
	local playing_num = g.user_mgr:getPlayingUserNum()
	local users = g.user_mgr:getSeatUsers()
	for _, user in pairs(users) do
		if user:isGaming() and user:getAction() ~= user.s_bet_allin then
			oper_count = oper_count + 1
		end
	end
	if oper_count == 1 then
		--print("##########playerOper#####gaming player = 1")
		if playing_num == 1 then
			--都弃牌了
			self:changeStage(self.s_stage_over)
			return true
		elseif stage and stage ~= self.s_stage_preflop then
			--有人allin，直接跳到后续状态
			self:nextStage(100)
			return true
		end
	end
	--获取当前操作的玩家，等待其操作
	local next_oper = self:findNextOper()
	--没有下个操作者，进入下一轮
	if not next_oper then
		if playing_num >= self.start_play_limit then
			if stage then
				g.sleep(100) --停秒
			end
			self:nextStage()
			return true
		else
			self:changeStage(self.s_stage_over)
		end
		return
	end
	if oper_count == 1 and playing_num == 2 then
		--只有2个玩家时，上一个玩家allin 金额<=我下注金额，我不用再操作
		--如果2个人玩，大盲位不够交大盲， 小盲位还是要操作一下，因为self.stage_bet 至少是大盲 (self.stage_bet >= self.total_bet
		print("#####playerOper###oper_count1#######", self.stage_bet, next_oper:getStageBet(), next_oper:getUid(), next_oper:getSeatId())
		local follow_bet = self.stage_bet - next_oper:getStageBet()
		if follow_bet == 0 or self.stage_bet >= self.total_bet then
			--不需要操作
			self:nextStage()
			local sleep_time = 100
			if stage == self.s_stage_preflop then --大盲位不够交大盲时
				sleep_time = 200
			end
			g.sleep(sleep_time) --停1秒
			return true
		end
	end
	if self.cur_oper and next_oper:isSame(self.cur_oper) then
		g.log:deskInfo(0, "playerOper oper is same one:", self.cur_oper_seat_id)
		local follow_bet = self.stage_bet - self.cur_oper:getStageBet()
		if follow_bet == 0 then
			--不可能是同一个人操作2次
			self:nextStage()
			return true
		end
	end
	self.cur_oper = next_oper
	self.cur_oper_seat_id = self.cur_oper:getSeatId()
	self:pushNextOper()

	--设置个超时，如果不操作就自动操作弃牌
	local function fun()
		if not self.cur_oper then return end
		self.cur_oper:addNoOperNum()
		self.cur_oper:checkLeave()

		--过牌或者弃
		local can_bet = false
		if self.cur_oper:getStageBet() == self.stage_bet then
			can_bet = self:betting(self.cur_oper_seat_id, 0)
		end
		if not can_bet then
			--弃牌
			self:betting(self.cur_oper_seat_id, -1)
		end
		self:playerOper()
	end
	local oper_time = self.stateTime.oper
	if self.cur_oper:getAutoPlay() == 1 then
		oper_time = 1.5
	end
	--操作定时
	self.oper_timer_id = self.oper_timer:timeout(oper_time, fun)

end

--翻牌前
function Desk:stPreflop()
	g.log:deskInfo(0, "stPreflop:")
	local users = g.user_mgr:getPlayingUser()
	--前注
	if self.pre_bet > 0 then
		for k, user in pairs(users) do
			local bb_act = user.s_bet_pre
			if user:getChip() < self.pre_bet then
				bb_act = user.s_bet_allin
			end
			self:betting(user:getSeatId(), self.pre_bet, bb_act)
		end
	end
	--下大小盲注
	local bb_act = self.bb_user.s_bet_bb
	if self.bb_user:getChip() < self.bb then
		bb_act = self.bb_user.s_bet_allin
	end
	local sb_act = self.sb_user.s_bet_sb
	if self.sb_user:getChip() < self.sb then
		sb_act = self.sb_user.s_bet_allin
	end
	self:betting(self.bb_user:getSeatId(), self.bb, bb_act)
	self:betting(self.sb_user:getSeatId(), self.sb, sb_act)
	--如果是新入玩家可能要加前注
	--if self.old_player_num > 1 then
	--	local users = g.user_mgr:getPlayingUser()
	--	for _, user in pairs(users) do
	--		if user:getRound() == 1 then
	--			local bb_act = user.s_bet_pre
	--			if user:getChip() < self.bb then
	--				bb_act = user.s_bet_allin
	--			end
	--			local pre_bet = self.bb - user:getSeatBet()
	--			if pre_bet > 0 then
	--				self:betting(user:getSeatId(), pre_bet, bb_act)
	--			end
	--		end
	--	end
	--end
	--每个玩家发2个牌
	for _, user in pairs(users) do
		local cards = g.rule:getNextCards(2)
		user:setCards(cards)
		local rank = g.rule:evaluate(cards, {}) --牌型
		user:setHandRank(rank)
	end
	self:pushPreflop()
	self:playerOper(self.s_stage_preflop)
	local user_cards = nil
	for _, user in pairs(users) do
		user_cards = user:getCards()
		local rank = g.rule:evaluate(user:getCards(), self.final_cards) --牌型
		g.log:deskWarn(user:getUid(), "user_cards", user_cards)
		user:setFinalRank(rank) --最终的牌值
	end

end

function Desk:stFlop()
	g.log:deskInfo(0, "stFlop")
	--入局了
	local users = g.user_mgr:getPlayingUser()
	for _, user in pairs(users) do
		user:setVPIP(1)
		user:setPFR(1)
		if user:getSeatBet() > self.bb + self.pre_bet then
			user:setPFR(2)
		end
	end
	--发3张公牌
	self.common_cards = {}
	for i=1, 3 do
		table_insert(self.common_cards, self.final_cards[i])
	end

	self:pushPot()
	self:showCards()
	self:pushFlop(self.common_cards)
	self:playerOper(self.s_stage_flop)

end

function Desk:stTurn()
	g.log:deskInfo(0, "stTurn")
	--发1张公牌
	local card = self.final_cards[4]
	table_insert(self.common_cards, card)
	local cards = {card}
	self:pushPot()
	self:showCards()
	self:pushTurn(cards)
	self:playerOper(self.s_stage_turn)
end

function Desk:stRiver()
	g.log:deskInfo(0, "stRiver")
	--发1张公牌
	local card = self.final_cards[5]
	table_insert(self.common_cards, card)
	local cards = {card}
	self:pushPot()
	self:showCards()
	self:pushRiver(cards)
	self:playerOper(self.s_stage_river)
end

--结束游戏
function Desk:stOver()
	self:pushPot()
	--游戏结束做结算统计
	local users = g.user_mgr:getSeatUsers()
	local seat_win = {} --{seat_id = xx} 赢家位置
	local pot_seats_win = {} --池中那个玩家位赢
	local has_pots = false
	local win_pot_num = 0 --有人赢的池数
	if self.pots[1] == 0 then
		--没有分池
		local win_rank = nil --赢的牌型
		local win_seat_ids = {} --赢的位置
		for _, user in pairs(users) do
			if user:isGaming() then
				if not win_rank or user:getRank() < win_rank then --rank越小，牌型越大
					win_rank = user:getRank()
				end
			end
		end
		for sid, user in pairs(users) do
			if user:isGaming() then
				if not win_rank or user:getRank() == win_rank then
					table_insert(win_seat_ids, sid)
				end
			end
			if user:getSeatBet() > 0 then
				self.pot_seats[1][sid] = true
			end
		end
		local win_num = #win_seat_ids
		local win_avg_pot = math_floor(self.total_bet/ win_num) --池的平均数
		local remainder = self.total_bet % win_num
		for i, sid in pairs(win_seat_ids) do
			seat_win[sid] = (seat_win[sid] or 0) + win_avg_pot
			if not pot_seats_win[1] then pot_seats_win[1] = {} end
			pot_seats_win[1][sid] = win_rank
			if i == 1 and remainder > 0 then
				seat_win[sid] = seat_win[sid] + remainder
			end
		end
	else
		--有分池产生
		has_pots = true
		local pot_rank = 0 --池中最大牌rank
		--比较每个池的牌值大小得到赢家
		for k, v in pairs(self.pot_seats) do
			local win_seat_ids = {} --赢的位置
			local win_rank = nil --赢的牌型
			local win_num = 0 --赢的人数
			local win_avg_pot = 0 --池是的平分数
			if not next(v) then
				break
			end
			--print("#######1#####pot_seats#####", tostring(v))
			for sid, b in pairs(v) do
				local user = g.user_mgr:getSeatUser(sid)
				if b and user and user:isGaming() then
					if not win_rank or user:getRank() < win_rank then
						--一个池中最大的牌型
						win_rank = user:getRank()
					end
				end
			end
			--print("#######2#####pot_seats#####", win_rank)
			for sid, b in pairs(v) do
				local user = g.user_mgr:getSeatUser(sid)
				if b and user and user:isGaming() then
					if user:getRank() == win_rank then
						table_insert(win_seat_ids, sid)
						user:addWinPot(k)
					end
				end
			end
			win_num = #win_seat_ids
			if win_num <= 0 then
				g.log:deskErr(0, "no winner err", v)
				return
			end
			win_avg_pot = math_floor(self.pots[k]/ win_num) --池的平均数
			local remainder = self.pots[k] % win_num
			for i, sid in pairs(win_seat_ids) do
				seat_win[sid] = (seat_win[sid] or 0) + win_avg_pot
				if not pot_seats_win[k] then pot_seats_win[k] = {} end
				pot_seats_win[k][sid] = win_rank
				if i == 1 and remainder > 0 then
					seat_win[sid] = seat_win[sid] + remainder
				end
			end
			if table.size(v) > 1 then --池中人数>1, 每个池中rank不相等
				if pot_rank ~= win_rank then
					win_pot_num = win_pot_num + 1
					pot_rank = win_rank
				end
			end
		end
	end
	local player_num = g.user_mgr:getPlayingUserNum()
	local users = g.user_mgr:getPlayingUser()
	for _, user in pairs(users) do
		user:setWTSD(1)
		local sid = user:getSeatId()
		if seat_win[sid] then --亮牌后赢了
			user:setWSD(1)
		end
	end
	g.log:deskInfo(0, string.format("gameover seat_win:%s common_cards:%s", seat_win, tostring(self.common_cards)))
	self:addChip(seat_win)
	--发送输赢结果
	self:pushGameover(pot_seats_win)
	if self.closed then --桌子要关闭，不用再等，直接写入记录
		--输赢日志
		self:sendTableLogs()
	end
	--最好牌
	self:sendBestCards()
	--亮牌
	self:pushShowcards2()




	--有人赢的池数多时间要跟着变
	--都弃牌只需要2.4S时长
	local delay_time = self.stateTime.over
	if win_pot_num > 1 then
		delay_time = delay_time + math_floor(4 * (win_pot_num-1))
	end
	if player_num == 1 then
		--弃牌
		delay_time = 4
	end
	--g.log:info("gameover delay time:", delay_time)
	local callback = function ()
		if not self.closed then
			--输赢日志
			self:sendTableLogs()
		end
		self:changeStage(self.s_stage_rest)
	end
	self.oper_timer_id = self.oper_timer:timeout(delay_time, callback)

end

--休息
function Desk:stReset()
	g.log:deskInfo(0, "stReset")
	--重置数据
	self:reset()
	self:checkUser()
	local delay = 0
	local user_num = 0
	--有2个以上的玩家才可以开始玩
	g.fork(function()
		while true do
			user_num = g.user_mgr:getSeatUsersNum()
			if self.closed then
				self:checkUser()
				return true
			end
			if self.started then
				--收到开始通知
				if user_num >= self.start_play_limit then
					delay = 0
					--0.3秒后开始
					g.sleep(self.stateTime.rest*30)
					if user_num >= self.start_play_limit then
						break
					end
				end
				if user_num == 1 then
					--如果只剩下一个人时隔15秒检查一下是否要合桌
					delay = delay + 1
					if delay > 10 then
						delay = 0
						self:mergeDesk()
					end
				end
			end
			g.sleep(100)
		end
		self:changeStage(self.s_stage_start)
		return true
	end)

end

--检查用户状态
function Desk:checkUser()
	--如果玩家已经不够币, 站起
	local users = g.user_mgr:getSeatUsers()
	for sid, user in pairs(users) do
		local uid = user:getUid()
		if user:getChip() <= 0 then
			g.user_mgr:standUp(uid)
			self:sendUsers("TS_2C_standupBc", {
				mid = uid,
				tid = g.desk_id,
				seatid = sid,
			})
			if user:isRobot() then
				g.user_mgr:removeUser(uid)
			end
		end
	end
	if self.closed then return end
	--合桌请求
	self:mergeDesk()

end

--比赛正式开始
function Desk:matchStart()
	if self.started then return end
	self.started = true
	--self.blind_level = g.room_cfg.blind_level
	--local bid = g.room_cfg.bid
	--self.blinds = g.blind_cfg[bid] or g.blind_cfg[1]
	--self.blind_cfg = self.blinds[self.blind_level]
	--self.up_blind_time = self.blind_cfg.up_time
	self:reset()
	--print("#######self.blind_level", self.blind_level)
	--print("##########", self.blind_cfg)
	--g.sleep(30)
	self:sendRoomStart()
end

--升级盲注
function Desk:upBlindTime(msg)
	self.blind_level = msg.blind_level
	self.blind_cfg = self.blinds[self.blind_level]
	self.up_blind_time = msg.up_blind_time
	if self:getStage() == self.s_stage_rest then
		self.sb = math.floor(self.blind_cfg.small_blind)
		self.bb = self.sb * 2
	end
	self:pushUpBlindTime()
end

--比赛暂停
function Desk:matchPause(is_pause)
	if is_pause then
		self.started = false
	else
		self.started = true
	end
	g.log:deskWarn(0, "matchPause")
end

--比赛场配置
function Desk:matchData(msg)
	g.log:deskInfo(0, "matchData: ", msg)
	g.room_cfg = table.copy(msg)
	g.room_cfg.min_buy = 0
	g.room_cfg.max_buy = 1000000000000
	g.room_cfg.max_limit = 1000000000000
	g.room_cfg.fee_rate = 0
	g.room_cfg.min_fee = 0
	g.room_cfg.max_fee = 0
	local bid = msg.bid
	self.blind_level = msg.blind_level
	if self.blind_level == 0 then
		self.blind_level = 1
	end
	self.blinds = g.blind_cfg[bid] or g.blind_cfg[1]
	self.blind_cfg = self.blinds[self.blind_level]
	self.up_blind_time = msg.up_blind_time

	--人坐下后开始游戏
	g.timeout(3, function()
		self:matchStart()
	end)
end

----------------------------------
-- 数据操作
----------------------------------

--玩家下注
function Desk:onBet(uid, msg)
	g.log:deskInfo(uid, "onBet ", self:getStage(), tostring(msg))
	local user = g.user_mgr:getUser(uid)
	if not user or not user:isGaming() then
		return {code = g.error_code.fail, tid = g.desk_id,}
	end
	local seat_id = user:getSeatId()
	local chips = math_floor(msg.chips)
	if not self.cur_oper_seat_id or seat_id ~= self.cur_oper_seat_id then
		g.log:deskWarn(uid, string.format("onBet seat_id:%s, cur_oper_seat_id:%s", seat_id, self.cur_oper_seat_id))
		return {
			code = g.error_code.fail,
			tid = g.desk_id,
		}
	end
	if self:getStage() ~= self.s_stage_preflop and self:getStage() ~= self.s_stage_flop and self:getStage() ~= self.s_stage_turn and
			self:getStage() ~= self.s_stage_river then
		g.log:deskErr(uid, "onBet err ", self:getStage(), tostring(msg))
		return {code = g.error_code.fail, tid = g.desk_id,}
	end

	local can_bet = self:betting(seat_id, chips)
	if not can_bet then
		g.log:deskWarn(uid,"onBet can_bet false ")
		return {code = g.error_code.fail, tid = g.desk_id,}
	end
	user:checkComeback()
	if self:getStage() == self.s_stage_preflop then
		if chips == -1 then
			user:addGiveupNum()
		else
			user:setGiveupNum(0)
		end
	end
	--停止定时器
	self.oper_timer:deltimer(self.oper_timer_id)
	self:setRank(user)
	self:playerOper() --继续下一个玩家操作


	return {code = g.error_code.ok}
end

function Desk:getStageNum()
	local stage = self:getStage()
	return self.state_num[stage] or 0
end

--关闭房间
function Desk:destroy()
	self.closed = true
end

--计算牌值
function Desk:setRank(user)
	if not user:isGaming() and not user:isGiveup() then
		--没有在游戏中
		return
	end
	local hand_cards = user:getCards()
	local common_cards = self.common_cards
	if not next(hand_cards) and not next(common_cards) then
		return
	end
	if not next(common_cards) then
		user:setKind(1)
		--只有2张牌可以计算对子
		local card1 = hand_cards[1] & 0x0F
		local card2 = hand_cards[2] & 0x0F
		if card1 == card2 then
			user:setKind(2)
		end
		return
	end

	local rank = g.rule:evaluate(hand_cards, common_cards) --牌型
	local kind = g.rule:getKind(rank)
	user:setRank(rank)
	user:setKind(kind)
	local best_cards = g.rule:getBestCards(kind, hand_cards, common_cards)
	user:setBestCards(best_cards)
end

-------------------------------------------------------------------------------
-- 推送消息
-------------------------------------------------------------------------------

function Desk:pushStart()
	local tb = {
		mids={},
		chips={},
	}
	local users = g.user_mgr:getSeatUsers()
	for _, user in pairs(users) do
		table_insert(tb.mids, user:getUid())
		table_insert(tb.chips, user:getChip())
	end
	local data = {
		tid = g.desk_id,
		msg = cjson.encode(tb),
		lid = self.lid,
		sb = self.sb,
		bb = self.bb,
		up_blind_time = self.up_blind_time,
	}
	self:sendUsers("TS_2C_gamebeginBc", data)
	self:pushButton()
	--g.log:finfo("__________ps_ntStart", data)
end

--本局庄家
function Desk:pushButton()
	local data = {
		tid = g.desk_id,
		seatid = self.banker_seat_id,
		sb = self.sb_user:getSeatId(),
		bb = self.bb_user:getSeatId(),
	}
	self:sendUsers("TS_2C_buttonBc", data)
end

--翻牌前
function Desk:pushPreflop()
	local users = g.user_mgr:getUsers()
	for _, user in pairs(users) do
		if user:isGaming() or user:isGiveup() then
			self:setRank(user)
			local cards = user:getClientCards()
			local data = {
				tid = g.desk_id,
				card = cards,
				kind = user:getKind(),
			}
			self:sendUser(user, "TS_2C_preflop", data)
		else
			self:sendUser(user, "TS_2C_preflop", { tid=g.desk_id, card={}, kind=1 })
		end
	end
end

--翻牌
function Desk:pushFlop(cards)
	local users = g.user_mgr:getUsers()
	local card = {}
	for _, v in pairs(cards) do
		table_insert(card, {card=v})
	end
	for _, user in pairs(users) do
		if user:isGaming() or user:isGiveup() then
			self:setRank(user)
			local data = {
				tid = g.desk_id,
				card = card,
				kind = user:getKind(),
			}
			self:sendUser(user, "TS_2C_flopBc", data)
		else
			self:sendUser(user, "TS_2C_flopBc", { tid=g.desk_id, card=card, kind=1 })
		end
	end
end


--转牌
function Desk:pushTurn(cards)
	local users = g.user_mgr:getUsers()
	local card = {}
	for _, v in pairs(cards) do
		table_insert(card, {card=v})
	end
	for _, user in pairs(users) do
		if user:isGaming() or user:isGiveup() then
			self:setRank(user)
			local data = {
				tid = g.desk_id,
				card = card,
				kind = user:getKind(),
			}
			self:sendUser(user, "TS_2C_turnBc", data)
		else
			self:sendUser(user, "TS_2C_turnBc", { tid=g.desk_id, card=card, kind=1 })
		end
	end
end

--河牌
function Desk:pushRiver(cards)
	local users = g.user_mgr:getUsers()
	local card = {}
	for _, v in pairs(cards) do
		table_insert(card, {card=v})
	end
	for _, user in pairs(users) do
		if user:isGaming() or user:isGiveup() then
			self:setRank(user)
			local data = {
				tid = g.desk_id,
				card = card,
				kind = user:getKind(),
			}
			self:sendUser(user, "TS_2C_riverBc", data)
		else
			self:sendUser(user, "TS_2C_riverBc", { tid=g.desk_id, card=card, kind=1 })
		end
	end
end

--下一个下注的用户
function Desk:pushNextOper()
	self.follow_bet = self.stage_bet - self.cur_oper:getStageBet()
	local data = {
		tid = g.desk_id,
		mid = self.cur_oper:getUid(),
		seatid = self.cur_oper:getSeatId(),
		time = self.stateTime.oper,
		min_bet = self.min_raise_bet, --最小加值
		max_bet = self.cur_oper:getChip(),
		follow_bet = self.follow_bet,
		delay = self.oper_timer:getCD(self.oper_timer_id),
	}
	--print("##########pushNextoper####", tostring(data))
	self:sendUsers("TS_2C_nextbetBc", data)
	--机器人操作
	if self.cur_oper:isRobot() then
		g.robo_oper:betChip(self.cur_oper)
	end
end

--广播下注
function Desk:pushBet(bet, user)
	--print("#######pushBet  ", bet)
	--user = user or self.cur_oper
	local uid = user:getUid()
	local data = {
		tid = g.desk_id,
		mid = uid,
		seatid = user:getSeatId(),
		seat_chips = user:getChip(),
		bet = user:getStageBet(), --本轮已下注
		action = user:getAction(),
	}
	self:sendUsers("TS_2C_betBc", data)
end

--奖池
function Desk:pushPot()
	--self:calcPots()
	local pots = {}
	if self.pots[1] == 0 then
		--没有分池的情况
		print("##########pushPot1 ", self.total_bet)
		table_insert(pots, {pot=self.total_bet})
	else
		print("##########pushPot2 ", self.pots[1])
		for k, v in pairs(self.pots) do
			local pot = {pot = v}
			table_insert(pots, pot)
		end
	end
	local data = {
		tid = g.desk_id,
		pots = pots,
	}
	self:sendUsers("TS_2C_potBc", data)
end


--游戏结束
function Desk:pushGameover(pot_seats_win)
	--		.Guser {
	--	mid 0 : integer
	--	seatid 1 : integer
	--	cards 2 : *Card
	--	kind 3 : integer
	--	win 4 : string
	--	seat_chips 5 : string
	--	pot_indexs 6 : *PotIndex
	--	info 7 : string
	--	rank 8 : integer
	--}
	local user_data = {}
	local gusers = {}
	local play_num = g.user_mgr:getPlayingUserNum()
	local users = g.user_mgr:getSeatUsers()
	for sid, v in pairs(users) do
		local cards = {}
		local pot_indexs = {} --池子与玩家数
		if v:isGaming() then
			for i, pots in pairs(self.pot_seats) do
				local count = table.size(pots)
				if pots[sid] and count > 0 and pot_seats_win[i] and pot_seats_win[i][sid] then
					table_insert(pot_indexs, {pos = i, count = count})
				end
			end
			if play_num > 1 then
				cards = v:getClientCards()
				v:setShowCards(v:getCards())
			end
		else
			--弃牌，没有在玩的
		end
		local uid = v:getUid()
		local data = {
			mid = v:getUid(),
			seatid = v:getSeatId(),
			kind = v:getKind(),
			seat_chips = v:getChip(),
			rank = v:getRank(),
			win = v:getWinChip(),
			cards = cards,
			pot_indexs = pot_indexs,
		}
		table_insert(gusers, data)


		local tsid = (v:getSeatId() - self.banker_seat_id) --相对庄的位置
		user_data[uid] = {
			mid = uid,
			seat_id = v:getSeatId(),
			chip = v:getChip(),
			start_time = v:getStartTime(),
			end_time = g.time(),
			remote = v:getRemote(),
			agent = v:getAgent(),
			total_bet = v:getSeatBet(), --本局总下注
			sid = tsid > 0 and tsid or self.seat_count - tsid,
			tid = g.tid,
		}
	end
	local data = {
		users = gusers,
		tid = g.desk_id,
	}
	self:sendUsers("TS_2C_gameoverBc", data)
	g.log:deskInfo(0, "match_gameover:", self.total_bet, tostring(data))

	--通知房间管理
	local data = {
		users = user_data,
		tid = g.desk_id,
	}
	self:sendRoomGameOver(data)


	g.robo_oper:gameOver(gusers)
end
--
----开牌
--function Desk:pushShowcards(users)
--	local cards = {}
--	for _, user in pairs(users) do
--		local sid = user:getSeatId()
--		local card = {seatid = sid, cards=user:getClientCards(), from = 0,}
--		table_insert(cards, card)
--		self.user_show_cards[sid] = nil
--	end
--	local data = {
--		tid = g.desk_id,
--		cards = cards,
--	}
--	self:sendUsers("TS_2C_showcardsBc", data)
--end
--
----结束时亮牌
--function Desk:pushShowcards2()
--	if not next(self.user_show_cards) then
--		return
--	end
--	local cards = {}
--	for sid, card in pairs(self.user_show_cards) do
--		local scard = {seatid = sid, cards=card, from = 1,}
--		table_insert(cards, scard)
--	end
--	self.user_show_cards = {}
--	local data = {
--		tid = g.desk_id,
--		cards = cards,
--	}
--	self:sendUsers("TS_2C_showcardsBc", data)
--end

--涨盲
function Desk:pushUpBlindTime()
	local data = {
		tid = g.desk_id,
		pre_bet = self.blind_cfg.pre_bet,
		sb = self.blind_cfg.small_blind,
		up_blind_time = self.up_blind_time,
	}
	self:sendUsers("TS_2C_upblindBc", data)
end

--离线处理
function Desk:disconnectCallback(user)
	local uid = user:getUid()
	if user:isGaming() then
		return true
	end
	if user:getChip() > 0 then
		return true
	end
	local sid = user:getSeatId()
	--没金币的可以离开
	if user:isSeating() then
		g.user_mgr:standUp(uid)
		self:sendOther(uid, "TS_2C_standupBc", {
			mid = uid,
			tid = g.desk_id,
			seatid = sid,
		})
	end
	--从user_manager中删除
	g.user_mgr:removeUser(uid)
	self:sendOther(uid, "TS_2C_leaveBc", {
		mid = uid,
		tid = g.desk_id,
		seatid = user:getSeatId(),
	})

	return true
end

function Desk:enterDeskCallback(user, msg)
	if user:isSeating() then return end
	local uid = user:getUid()
	if msg.rtype and msg.rtype == g.const.room_type.match and msg.chips > 0 then
		if msg.tid then
			--如果在当前比赛场的别的桌子坐下了就不能再在这个桌子坐下
			if msg.playing_tid and msg.playing_tid ~= g.tid then
				return
			end
			--检查是否报名过
			local sign = g.dp:getMatchSign(g.rid, uid)
			g.log:deskInfo(uid, "enterDeskCallback", sign)
			if sign  then
				msg.chips = g.room_cfg.chips
				--比赛场自动坐下
				g.fork(function()
					g.sleep(100)
					g.chandler:reqSitDown(msg)
				end)
			end
		else
			--检查是否报名过
			local sign = g.dp:getMatchSign(g.rid, uid)
			g.log:deskInfo(uid, "enterDeskCallback getMatchSign:", sign)
			if sign then
				msg.chips = g.room_cfg.chips
				--比赛场自动坐下
				g.fork(function()
					g.sleep(100)
					g.chandler:reqSitDown(msg)
				end)
			end
		end
	end
end

function Desk:leaveCallback(user)
	local uid = user:getUid()
	if user:isSeating() then
		return {
			code = g.error_code.ok,
			tid = g.tid,
		}
	end
	if user:getChip() > 0 then
		return {
			code = g.error_code.ok,
			tid = g.tid,
		}
	end
	g.log:deskInfo(uid, "leaveCallback ", user:getChip(), user:isSeating())
	g.user_mgr:removeUser(uid)

	return {
		code = g.error_code.ok,
		tid = g.tid,
	}
end

--站起
function Desk:standUpCallback(user)
	--如果在游戏中，弃牌
	local uid = user:getUid()
	local seat_id = user:getSeatId()
	if user:isGaming() then
		--user:setStatus(user.s_status_giveup)
		if self.cur_oper_seat_id == seat_id then
			self.oper_timer:deltimer(self.oper_timer_id)
		end
		self:betting(seat_id, -1) --弃牌
		--如果当前可操作人数为1，直接进入over状态
		local count = g.user_mgr:getOperPlayerNum()
		if count == 1 then
			print("###############gaming player = 1")
			if g.user_mgr:getPlayingUserNum() == 1 and self:getStageNum() < self.state_num[self.s_stage_over] then
				self:changeStage(self.s_stage_over)
			end
		end
	end
	if user:isSeating() then
		self:sendUsers("TS_2C_standupBc", {
			mid = uid,
			tid = g.desk_id,
			seatid = user:getSeatId(),
		})
	end
end

-- 合桌
function Desk:mergeDesk()
	--g.log:deskInfo(0, "mergeDesk ")
	--先把要合桌的人放到一个列表，等游戏一局结束后进行合桌
	--合桌对，座位有一定的要求， 庄，大小盲间不能有空位
	local user_num =  g.user_mgr:getSeatUsersNum()
	if user_num < self.seat_count - 2 then
		--可以拆桌
		local res = g.callGames("check_merge", {tid = g.desk_id, user_num = user_num, rid = g.rid})
		g.log:deskInfo(0, "check_merge res:", res)
		if res and next(res) then
			--有桌子可进入
			local new_desk = nil
			local users = g.user_mgr:getSeatUsers()
			for sid, user in pairs(users) do
				local svr = table_remove(res)
				local uid = user:getUid()
				local ok = g.call(svr, "merge_desk", {user_data=user:getUserData(), mid=uid, chips=user:getChip(), info=user:getInfo(), tid=g.tid})
				if ok then
					--离桌处理
					g.user_mgr:removeUser(uid)
					g.dp:clearMatchUser(g.rid, g.tid, uid)
					new_desk = svr
				end
			end

			--已经合桌， 把闲人踢出桌子
			local user_num = g.user_mgr:getSeatUsersNum()
			if user_num == 0 then
				local users = g.user_mgr:getUsers()
				for uid, user in pairs(users) do
					if new_desk and user:getChip() == 0 and user:isPlayer() then
						local ok = g.call(new_desk, "merge_desk", {user_data=user:getUserData(), mid=uid, chips=0, info=user:getInfo(), tid=g.tid})
						if ok then
							--离桌处理
							g.user_mgr:removeUser(uid)
						end
					else
						g.user_mgr:removeUser(uid)
					end
					--self:sendUser(user, "TS_2C_leaveBc", {
					--	mid = uid,
					--	tid = g.desk_id,
					--	seatid = user:getSeatId(),
					--})
				end
			end

		end
	end
end

function Desk:showCards()
	local state = self:getStage()
	if self.state_num[state] <= self.state_num[self.s_stage_preflop] then
		return
	end
	if self.allined then
		return
	end
	local users = g.user_mgr:getPlayingUser()
	local users_num = g.user_mgr:getPlayingUserNum()
	local allin_num = 0
	for _, user in pairs(users) do
		if user:getAction() == user.s_bet_allin then
			allin_num = allin_num + 1
		end
	end
	if users_num - 1 <= allin_num then
		if not self.allined then
			--把所有人的牌亮出来
			self:pushShowcards(users)
			g.sleep(200)
		end
		self.allined = true
	end
end


function Desk:setUserShowCard(sid, cards)
	self.user_show_cards[sid] = cards
	if self:getStage() == self.s_stage_over then
		self:pushShowcards2()
	end
end

--通知房间管理
function Desk:sendRoomGameOver(data)
	g.sendGames("game_over", g.rid, data)
end

--比赛结束了
function Desk:matchClose(msg)
	g.log:deskInfo(0, "matchClose:", msg)
	g.timeout(6, function()
		local users = g.user_mgr:getUsers()
		for uid, user in pairs(users) do
			local rank = msg[uid] or 0
			self:sendUser(user, "TS_2C_matchOverBc", {tid=g.tid, rank=rank})
		end
	end)
	g.timeout(10, function()
		g.user_mgr:removeUsers()
		self:onClose()
	end)
end

function Desk:sendRoomStart()
	local users = g.user_mgr:getSeatUsers()
	local user_data = {}
	if not next(users) then return end
	for sid, v in pairs(users) do
		local uid = v:getUid()
		user_data[uid] = {
			mid = uid,
			seat_id = v:getSeatId(),
			chip = v:getChip(),
			start_time = v:getStartTime(),
			end_time = 0,
			remote = v:getRemote(),
			agent = v:getAgent(),
			total_bet = v:getSeatBet(), --本局总下注
			sid = sid, --靠近庄的相对位
			tid = g.tid,
		}
	end
	--通知房间管理
	local data = {
		users = user_data,
		tid = g.tid,
	}
	g.sendGames("game_start", g.rid, data)
	--g.log:deskInfo("11111111111", data)
end


--返回桌子信息
function Desk:getDeskInfo(uid)
	--print("#############getDeskInfo_________", uid)
	local cfg = g.room_cfg
	local user = g.user_mgr:getUser(uid)
	local seats = {}
	local users = g.user_mgr:getSeatUsers()
	local desk = g.desk
	for k, v in pairs(users) do
		local seat = {
			mid = v:getUid(),
			seatid = v:getSeatId(),
			seat_chips = v:getChip(),
			status = v:getStatus(),
			action = v:getAction(),
			bet = v:getStageBet(),
			online = v:getOnline(),
			info = v:getInfo(),
			other = "",
			auto_oper = v:getAutoPlay(),
		}
		table_insert(seats, seat)
	end
	local cards = g.desk:getCommonCards() --公牌
	local pots = g.desk:getPot() --分池
	local self_user = {}
	if user:isSeating() then
		self_user = {
			card = user:getClientCards(),
			kind = user:getKind(),
			min_bet = desk.min_raise_bet, --最小加注值
			max_bet = user:getChip(),
			folow_bet = desk.stage_bet,
		}
	end
	local sb, bb = g.desk:getBind()
	local status = desk:getStageNum()
	local cd_time = desk:getOperCDTime()
	if status > 5 then
		cd_time = 0
	end
	local roomInfo = {
		rid = g.rid,
		tid = g.desk_id,
		sb = sb,
		bb = bb,
		min_buy = math_floor(cfg.min_buy) or 0,
		max_buy = math_floor(cfg.max_buy) or 0,
		button = desk.banker_seat_id,
		cards = cards,
		pots = pots,
		curr_seatid = desk.cur_oper_seat_id or 0,
		cd_time = cd_time, --剩余操作时间
		all_time = desk.stateTime.oper, --总时间
		status = status, --桌子状态
		info = "",
		pre_bet = self.pre_bet or 0, --前注
		up_blind_time = desk.up_blind_time or 0, --涨盲时间
	}
	local res = {
		code = g.error_code.ok,
		seats = seats,
		roominfo = roomInfo,
		selfuser = self_user,
		seatid = user:getSeatId(),
		tid = g.tid,
		rid = g.rid,
		rtype = g.rtype,
	}

	return res
end

--操作时间
function Desk:getOperCDTime()
	local num = self:getStageNum()
	if num >= self.state_num[self.s_stage_preflop] or num <= self.state_num[self.s_stage_river] then
		return math_floor(self.oper_timer:getCD(self.oper_timer_id))
	end
	return 0
end

return Desk